import ipaddress
from tqdm import tqdm
from cuslog import CusLog
from runtimecalc import decorator
from reexpattern import *

version_info = (0, 9, 9)
versionstr = '.'.join(map(str, version_info))


def clear_nested_list(lst):
    """递归清空多维列表"""
    for i in range(len(lst)):
        if isinstance(lst[i], list):
            clear_nested_list(lst[i])
        else:
            # 如果不是列表，可以选择保留或清空
            # 这里我们选择清空所有元素
            pass
    lst.clear()

def clear_multidimensional_dict(d):
    """
    递归清空多维字典中的所有值
    """
    if isinstance(d, dict):
        for key in list(d.keys()):
            if isinstance(d[key], dict):
                clear_multidimensional_dict(d[key])
            d[key] = None  # 或者使用 del d[key]
        d.clear()


class EventProcess:
	def __init__(self, epconfigdict):

		#initialize variables
		self.currdayeventinfo = []
		self.processed_events = []
		self.session_info = {}
		self.directappdict = {}
		self.relayappdict = {}
		self.event_processed_count = {}
		self.func_process_map = {}

		#get config
		self.tqdmncols = epconfigdict.get('tqdmncols', 100)
		self.bar_format = epconfigdict.get('bar_format', '{l_bar}{bar}| {n_fmt}/{total_fmt} [{rate_fmt}]')

		#logset
		self.evlog = CusLog(log_type='eventprocess')

		#function map set
		self.func_process_map = {'1': self.type1_merge,
								 '2': self.typeunprocess,
								 '3': self.type3_merge,
								 '4': self.type4_merge,
								 '5': self.typeunprocess,
								 '6': self.typeunprocess,
								 '7': self.type7_merge,
								 '8': self.typeunprocess,
								 'a': self.typeunprocess,
								 }


	def init_eventdata(self, currdayeventinfo):
		clear_nested_list(self.currdayeventinfo)
		clear_nested_list(self.processed_events)
		clear_multidimensional_dict(self.session_info)
		self.event_processed_count = {'et1_s1_m1' : 0, 'et1_s1_m2' : 0, 'et1_s2_m1' : 0, 'et1_s3_m1' : 0,
									  'et3_s1_m1' : 0, 'et3_s1_m2' : 0, 'et3_s2_m1' : 0, 'et3_s3_m1' : 0, 'et3_s3_m2' : 0, 'et3_s3_m3' : 0, 'et3_s4_m1' : 0, 'et3_s5_m1' : 0,
									  'et4_s1_m1' : 0, 'et4_s1_m2' : 0, 'et4_s2_m1' : 0, 'et4_s2_m2' : 0,
									  'et7_s1_m1' : 0, 'et7_s2_m1' : 0, 'et7_s3_m1' : 0}
		self.currdayeventinfo = currdayeventinfo
	
	def clear_eventdata(self):
		clear_nested_list(self.currdayeventinfo)
		clear_nested_list(self.processed_events)
		clear_multidimensional_dict(self.session_info)
		self.event_processed_count = {}
	
	def init_appdict(self, directappdict, relayappdict):
		self.directappdict = directappdict
		self.relayappdict = relayappdict
	
	def process_currdata(self):
		#split event and get session info
		self.process_events()
		#update event with session info
		self.update_events()
	
	def logger_close(self):
		self.evlog.clear_handlers()
	
	def display_sessioninfo(self, filefh):
		for key in self.session_info:
			filefh.write(f"Key: {key}, Info: {self.session_info[key]}\n")
			#self.evlog.cusdebug(f"Key: {key}, Info: {self.session_info[key]}")


	def get_eventdata(self):
		return self.processed_events

	@decorator
	def process_events(self):
		currday = self.currdayeventinfo[0][0]
		self.evlog.cusinfo(f"Processing events for trading day {currday}")
		#for currevent in self.currdayeventinfo:
		for currevent in tqdm(self.currdayeventinfo, desc=f"Processing events {currday}", unit="event", unit_scale=True, ncols=self.tqdmncols, leave=False, bar_format=self.bar_format):
			#(apptype, appid, sessionid, frontid, userproductinfo, remark, ipv4, mac, id, relayip, relaymac, subappid, dcerrid, ipv6)
			(TRADINGDAY,BROKERID,USERID,USEREVENTTYPE,EVENTSEQUENCENO,EVENTDATE,EVENTTIME,USEREVENTINFO,INVESTORID,INSTRUMENTID,DRIDENTITYID,EXCHANGEID,INVESTUNITID) = currevent
			currresult = [TRADINGDAY, BROKERID, USERID, USEREVENTTYPE, EVENTSEQUENCENO, EVENTDATE, EVENTTIME, INVESTORID, INSTRUMENTID, DRIDENTITYID, EXCHANGEID, INVESTUNITID, USEREVENTINFO]
			#mapping process function
			self.func_process_map[USEREVENTTYPE](currresult, USEREVENTINFO)
		#display processed events
		for currcount in self.event_processed_count:
			self.evlog.cusinfo(f"{currcount} processed count: {self.event_processed_count[currcount]}")
	
	def type1_merge(self, currresult, USEREVENTINFO):
		USERID = currresult[2]
		INVESTORID = currresult[7]
		splitresult = self.type1_process(USEREVENTINFO)
		if splitresult:
			(addinfo, priority) = splitresult
			if(priority != 0):
				if(USERID is not None and USERID.strip() != ''):
					curruserid = USERID.strip()
				else:
					curruserid = INVESTORID.strip()
				self.update_session_info(curruserid, addinfo, priority=priority)
			self.processed_events.append(currresult + addinfo)
	
	def type3_merge(self, currresult, USEREVENTINFO):
		addinfo = self.type3_process(USEREVENTINFO)
		if addinfo:
			self.processed_events.append(currresult + addinfo)

	def type4_merge(self, currresult, USEREVENTINFO):
		addinfo = self.type4_process(USEREVENTINFO)
		if addinfo:
			self.processed_events.append(currresult + addinfo)

	def type7_merge(self, currresult, USEREVENTINFO):
		USERID = currresult[2]
		INVESTORID = currresult[7]
		splitresult = self.type7_process(USEREVENTINFO)
		if splitresult:
			(addinfo, priority) = splitresult
			if(priority != 0):
				if(USERID is not None and USERID.strip() != ''):
					curruserid = USERID.strip()
				else:
					curruserid = INVESTORID.strip()
				self.update_session_info(curruserid, addinfo, priority=priority)
			self.processed_events.append(currresult + addinfo)

	def typeunprocess(self, currresult, USEREVENTINFO):
		pass

	@decorator
	def update_events(self):
		#for currrecord in self.processed_events:
		currday = self.processed_events[0][0]
		for currrecord in tqdm(self.processed_events, desc=f"Updating events {currday}", unit="event", unit_scale=True, ncols=self.tqdmncols, leave=False, bar_format=self.bar_format):
			rec_sessionid = currrecord[15]
			if(rec_sessionid is not None):
				if(currrecord[2] is not None and currrecord[2].strip() != ''):
					rec_userid = currrecord[2].strip()
				else:
					rec_userid = currrecord[7].strip()
				#rec_frontid = currrecord[16]
				#print(rec_userid, rec_sessionid, rec_frontid)
				#rec_key = f"{rec_userid}@{rec_sessionid}@{rec_frontid}"
				rec_key = f"{rec_userid}@{rec_sessionid}"
				if(rec_key in self.session_info):
					if(currrecord[13] is None or currrecord[14] is None):
						currrecord[13] = self.session_info[rec_key]['apptype']['value']
						currrecord[14] = self.session_info[rec_key]['appid']['value']
					if(currrecord[25] is None and self.session_info[rec_key]['dcerrid']['value'] is not None and currrecord[13] != '3'):
						currrecord[25] = self.session_info[rec_key]['dcerrid']['value']
					if(currrecord[13] == '1' or currrecord[13] is None or currrecord[13].strip() == ''):
						if(currrecord[19] is None and self.session_info[rec_key]['ipv4']['value'] is not None):
							currrecord[19]  = self.session_info[rec_key]['ipv4']['value']
						if(currrecord[26] is None and self.session_info[rec_key]['ipv6']['value'] is not None):
							currrecord[26]  = self.session_info[rec_key]['ipv6']['value']
						if(currrecord[20] is None and self.session_info[rec_key]['mac']['value'] is not None):
							currrecord[20] = self.session_info[rec_key]['mac']['value']
						if(self.session_info[rec_key]['remarkid']['value'] is not None):
							currrecord[21] = self.session_info[rec_key]['remarkid']['value']
					else:
						if(currrecord[22] is None and self.session_info[rec_key]['ipv4']['value'] != currrecord[19]):
							currrecord[22] = currrecord[19]
							currrecord[19] = None
						elif(currrecord[22] is None and currrecord[26] is not None and self.session_info[rec_key]['ipv6']['value'] != currrecord[26]):
							currrecord[22] = currrecord[26]
							currrecord[26] = None
						if(currrecord[23] is None and self.session_info[rec_key]['mac']['value'] != currrecord[20]):
							currrecord[23] = currrecord[20]
							currrecord[20] = None
						if(currrecord[13] != '3'):
							if(self.session_info[rec_key]['ipv4']['value'] is not None):
								currrecord[19] = self.session_info[rec_key]['ipv4']['value']
							if(self.session_info[rec_key]['ipv6']['value'] is not None):
								currrecord[26] = self.session_info[rec_key]['ipv6']['value']
							if(self.session_info[rec_key]['mac']['value'] is not None):
								currrecord[20] = self.session_info[rec_key]['mac']['value']
							if(self.session_info[rec_key]['remarkid']['value'] is not None):
								currrecord[21] = self.session_info[rec_key]['remarkid']['value']
							if(self.session_info[rec_key]['subappid']['value'] is not None):
								currrecord[24] = self.session_info[rec_key]['subappid']['value']
						elif(currrecord[19] ==  self.session_info[rec_key]['relayip']['value'] or currrecord[20] == self.session_info[rec_key]['relaymac']['value']):
							currrecord[19] = None
							currrecord[20] = None
						if(currrecord[22] is None and self.session_info[rec_key]['relayip']['value'] is not None):
							currrecord[22] = self.session_info[rec_key]['relayip']['value']
						if(currrecord[23] is None and self.session_info[rec_key]['relaymac']['value'] is not None):
							currrecord[23] = self.session_info[rec_key]['relaymac']['value']
			self.check_and_update(currrecord)



			#print(currrecord)


	def type1_process(self, USEREVENTINFO):
		if(USEREVENTINFO[0:5] == '用户登录：'):
			result = repa_et1_s1_m1.match(USEREVENTINFO[5:])
			if result:
				(tempip, tempmac, userproductinfo, frontid, sessionid, remark, appid) = result.groups()
				(remarkipv4, remarkipv6, remarkmac, remarkid) = self.remark_process(remark)
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac, remarkipv4=remarkipv4, remarkmac=remarkmac, remarkipv6=remarkipv6)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, userproductinfo=userproductinfo, remark=remark, ipv4=ipv4, mac=mac, remarkid=remarkid, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et1_s1_m1'] += 1
				return addinfo, 1
			result = repa_et1_s1_m2.match(USEREVENTINFO[5:])
			if result:
				(tempip, tempmac, userproductinfo, appid, frontid, remark) = result.groups()
				(remarkipv4, remarkipv6, remarkmac, remarkid) = self.remark_process(remark)
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac, remarkipv4=remarkipv4, remarkmac=remarkmac, remarkipv6=remarkipv6)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, frontid=frontid, userproductinfo=userproductinfo, remark=remark, ipv4=ipv4, mac=mac, remarkid=remarkid, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et1_s1_m2'] += 1
				return addinfo, 0
		elif(USEREVENTINFO[0:4] == '[登录]'):
			result = repa_et1_s2_m1.match(USEREVENTINFO[4:])
			if result:
				(sessionid, tempip, tempmac, userproductinfo, appid, frontid, remark) = result.groups()
				(remarkipv4, remarkipv6, remarkmac, remarkid) = self.remark_process(remark)
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac, remarkipv4=remarkipv4, remarkmac=remarkmac, remarkipv6=remarkipv6)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, userproductinfo=userproductinfo, remark=remark, ipv4=ipv4, mac=mac, remarkid=remarkid, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et1_s2_m1'] += 1
				return addinfo, 1
		elif(USEREVENTINFO[0:7] == '登录补充信息：'):
			result = repa_et1_s3_m1.match(USEREVENTINFO[7:])
			if result:
				(frontid, sessionid, remark) = result.groups()
				(remarkipv4, remarkipv6, remarkmac, remarkid) = self.remark_process(remark)
				addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid, remark=remark, ipv4=remarkipv4, mac=remarkmac, remarkid=remarkid, ipv6=remarkipv6)
				self.event_processed_count['et1_s3_m1'] += 1
				return addinfo, 2
		else:
			if(USEREVENTINFO[0:7] != '用户登录失败：'):
				self.evlog.cusdebug(f"Unknown event info for type 1: {USEREVENTINFO}")
		return None
	
	def type3_process(self, USEREVENTINFO):
		if(USEREVENTINFO[0:3] == '报单：'):
			result = repa_et3_s1_m1.match(USEREVENTINFO[3:])
			if result:
				(tempip, tempmac, frontid, sessionid, appid) = result.groups()
				(apptype, appid, ip, mac, relayip, relaymac, _) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ip, mac=mac, relayip=relayip, relaymac=relaymac)
				self.event_processed_count['et3_s1_m1'] += 1
				return addinfo
			result = repa_et3_s1_m2.match(USEREVENTINFO[3:])
			if result:
				(tempip, tempmac, appid) = result.groups()
				(apptype, appid, ip, mac, relayip, relaymac, _) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, ipv4=ip, mac=mac, relayip=relayip, relaymac=relaymac)
				self.event_processed_count['et3_s1_m2'] += 1
				return addinfo
		elif(USEREVENTINFO[0:4] == '[报单]'):
			result = repa_et3_s2_m1.match(USEREVENTINFO[4:])
			if result:
				(sessionid, tempip, tempmac, appid) = result.groups()
				(apptype, appid, ip, mac, relayip, relaymac, _) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, ipv4=ip, mac=mac, relayip=relayip, relaymac=relaymac)
				self.event_processed_count['et3_s2_m1'] += 1
				return addinfo
		elif(USEREVENTINFO[0:3] == '撤单：'):
			result = repa_et3_s3_m1.match(USEREVENTINFO[3:])
			if result:
				(tempip, tempmac, frontid, sessionid) = result.groups()
				(ipv4, ipv6) = self.ipv4v6_process(tempip)
				addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=tempmac, ipv6=ipv6)
				self.event_processed_count['et3_s3_m1'] += 1
				return addinfo
			result = repa_et3_s3_m2.match(USEREVENTINFO[3:])
			if result:
				(frontid, sessionid, tempip, tempmac, appid) = result.groups()
				(apptype, appid, ip, mac, relayip, relaymac, _) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ip, mac=mac, relayip=relayip, relaymac=relaymac)
				self.event_processed_count['et3_s3_m2'] += 1
				return addinfo
			result = repa_et3_s3_m3.match(USEREVENTINFO[3:])
			if result:
				(frontid, sessionid, tempip, tempmac) = result.groups()
				(ipv4, ipv6) = self.ipv4v6_process(tempip)
				addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=tempmac, ipv6=ipv6)
				self.event_processed_count['et3_s3_m3'] += 1
				return addinfo
		elif(USEREVENTINFO[0:4] == '[撤单]'):
			result = repa_et3_s4_m1.match(USEREVENTINFO[4:])
			if result:
				(sessionid, frontid, tempip, tempmac, appid) = result.groups()
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et3_s4_m1'] += 1
				return addinfo
		elif(USEREVENTINFO[0:8] == '交易所撤单失败，'):
			result = repa_et3_s5_m1.match(USEREVENTINFO[8:])
			if result:
				(frontid, sessionid) = result.groups()
				addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid)
				self.event_processed_count['et3_s5_m1'] += 1
				return addinfo
		else:
			if(USEREVENTINFO[0:5] != '申请组合：' and USEREVENTINFO[0:3] != '询价：'
	  			and USEREVENTINFO[0:6] != '条件单触发：' and USEREVENTINFO[0:5] != '执行宣告：'
				and USEREVENTINFO[0:5] != '预埋报单：' and USEREVENTINFO[0:7] != '删除预埋报单：'
				and USEREVENTINFO[0:7] != '触发预埋报单：'
				and USEREVENTINFO[0:6] != '期权自对冲：' and USEREVENTINFO[0:7] != '执行宣告撤销：' and USEREVENTINFO[0:8] != '期权自对冲撤销：'
				and USEREVENTINFO[0:5] != '对冲设置：' and USEREVENTINFO[0:5] != '预埋撤单：' and USEREVENTINFO[0:7] != '触发预埋撤单：'):
				self.evlog.cusdebug(f"Unknown event info for type 3: {USEREVENTINFO}")
		return None


	def type4_process(self, USEREVENTINFO):
		if(USEREVENTINFO[0:5] == '报单失败：'):
			result = repa_et4_s1_m1.match(USEREVENTINFO[5:])
			if result:
				(frontid, sessionid, tempip, tempmac) = result.groups()
				(ipv4, ipv6) = self.ipv4v6_process(tempip)
				addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=tempmac, ipv6=ipv6)
				self.event_processed_count['et4_s1_m1'] += 1
				return addinfo
			result = repa_et4_s1_m2.match(USEREVENTINFO[5:])
			if result:
				(tempip, tempmac, appid) = result.groups()
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et4_s1_m2'] += 1
				return addinfo
		if(USEREVENTINFO[0:5] == '撤单失败，'):
			if('用户端AppID：' not in USEREVENTINFO):
				result = repa_et4_s2_m1.match(USEREVENTINFO[5:])
				if result:
					(frontid, sessionid, tempip, tempmac) = result.groups()
					(ipv4, ipv6) = self.ipv4v6_process(tempip)
					addinfo = self.addinfo_merge(sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=tempmac, ipv6=ipv6)
					self.event_processed_count['et4_s2_m1'] += 1
					return addinfo
			result = repa_et4_s2_m2.match(USEREVENTINFO[5:])
			if result:
				(frontid, sessionid, tempip, tempmac, appid) = result.groups()
				(apptype, appid, ipv4, mac, relayip, relaymac, ipv6) = self.appid_process(appid=appid, tempip=tempip, tempmac=tempmac)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, ipv6=ipv6)
				self.event_processed_count['et4_s2_m2'] += 1
				return addinfo
		else:
			if(USEREVENTINFO[0:4] != '[撤单]' and USEREVENTINFO[0:4] != '[报单]' and USEREVENTINFO[0:7] != '申请组合失败：'
	  			and USEREVENTINFO[0:9] != '执行宣告报单失败：'
	  			and USEREVENTINFO[0:7] != '询价报单失败：' and USEREVENTINFO[0:9] != '执行宣告撤单失败：'
	  			and USEREVENTINFO[0:7] != '对冲设置失败：'
	  			and USEREVENTINFO[0:10] != '期权自对冲报单失败：'
	  			and USEREVENTINFO[0:10] != '期权自对冲撤单失败：'):
				self.evlog.cusdebug(f"Unknown event info for type 4: {USEREVENTINFO}")
		return None

	def type7_process(self, USEREVENTINFO):
		if(USEREVENTINFO[0:7] == '采集信息上报：'):
			result = repa_et7_s1_m1.match(USEREVENTINFO[7:])
			if result:
				(frontid, sessionid, syslen, reportinfo) = result.groups()
				addresult = self.additional_info_process(reportinfo)
				if addresult:
					(dcerrid, clientappid, clientip, clientport, clientlogtime, relayappid, relayip, relayport, relaylogtime, reinvid, usertype) = addresult
				else:
					self.evlog.cusdebug(f"Additional info process failed for type 7: {USEREVENTINFO}")
					return None
				(apptype, appid, ipv4, mac, relayip, relaymac, subappid, ipv6) = self.appid_process_report(clientappid, relayappid, clientip, relayip)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, subappid=subappid, dcerrid=dcerrid, ipv6=ipv6)
				self.event_processed_count['et7_s1_m1'] += 1
				return addinfo, 3
		if(USEREVENTINFO[0:14] == '采集信息上报 采集信息不全：'):
			result = repa_et7_s1_m1.match(USEREVENTINFO[14:])
			if result:
				(frontid, sessionid, syslen, reportinfo) = result.groups()
				addresult = self.additional_info_process(reportinfo)
				if addresult:
					(dcerrid, clientappid, clientip, clientport, clientlogtime, relayappid, relayip, relayport, relaylogtime, reinvid, usertype) = addresult
				else:
					self.evlog.cusdebug(f"Additional info process failed for type 7: {USEREVENTINFO}")
					return None
				(apptype, appid, ipv4, mac, relayip, relaymac, subappid, ipv6) = self.appid_process_report(clientappid, relayappid, clientip, relayip)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, subappid=subappid, dcerrid=dcerrid, ipv6=ipv6)
				self.event_processed_count['et7_s2_m1'] += 1
				return addinfo, 3
		if(USEREVENTINFO[0:15] == '采集信息上报 日期格式不正确：'):
			result = repa_et7_s1_m1.match(USEREVENTINFO[14:])
			if result:
				(frontid, sessionid, syslen, reportinfo) = result.groups()
				addresult = self.additional_info_process(reportinfo)
				if addresult:
					(dcerrid, clientappid, clientip, clientport, clientlogtime, relayappid, relayip, relayport, relaylogtime, reinvid, usertype) = addresult
				else:
					self.evlog.cusdebug(f"Additional info process failed for type 7: {USEREVENTINFO}")
					return None
				(apptype, appid, ipv4, mac, relayip, relaymac, subappid, ipv6) = self.appid_process_report(clientappid, relayappid, clientip, relayip)
				addinfo = self.addinfo_merge(apptype=apptype, appid=appid, sessionid=sessionid, frontid=frontid, ipv4=ipv4, mac=mac, relayip=relayip, relaymac=relaymac, subappid=subappid, dcerrid=dcerrid, ipv6=ipv6)
				self.event_processed_count['et7_s3_m1'] += 1
				return addinfo, 3
		else:
			self.evlog.cusdebug(f"Unknown event info for type 7: {USEREVENTINFO}")
		return None
	
	def ipv4v6_process(self, ipstr):
		if re.search(ipv4_pattern, ipstr):
			return (ipstr, None)
		else:
			return (None, ipstr)
	
	def check_ip_private(self, ipstr):
		try:
			ip_obj = ipaddress.ip_address(ipstr)
			return ip_obj.is_private
		except ValueError:
			return False # unkonwn ip format treated as public
	
	def appid_process(self, appid=None, tempip=None, tempmac=None, remarkipv4=None, remarkmac=None, remarkipv6=None):
		appid = appid.strip()
		if appid in self.directappdict:
			if re.search(ipv4_pattern, tempip):
				return [self.directappdict[appid], appid, tempip, tempmac, None, None, None]
			else:
				return [self.directappdict[appid], appid, None, tempmac, None, None, tempip]
		elif appid in self.relayappdict:
			return [self.relayappdict[appid], appid, remarkipv4, remarkmac, tempip, tempmac, remarkipv6]
		elif appid == '':
			if remarkipv4 is not None or remarkipv6 is not None or remarkmac is not None:
				#unknown appid wirte to log
				return [None, None, remarkipv4, remarkmac, tempip, tempmac, remarkipv6]
			else:
				return [None, None, tempip, tempmac, None, None, remarkipv6]
		else:
			#unknown appid wirte to log
			return [None, appid, remarkipv4, remarkmac, tempip, tempmac, remarkipv6]
	
	def appid_process_report(self, clientappid, relayappid, clientip, relayip):
		if(relayappid.strip() != ''):
			appid = relayappid.strip()
		else:
			appid = clientappid.strip()

		if appid in self.directappdict:
			if re.search(ipv4_pattern, clientip):
				return [self.directappdict[appid], appid, clientip, None, None, None, None, None]
			else:
				return [self.directappdict[appid], appid, None, None, None, None, None, clientip]
		elif appid in self.relayappdict:
			if re.search(ipv4_pattern, clientip):
				return [self.relayappdict[appid], appid, clientip, None, relayip, None, clientappid, None]
			else:
				return [self.relayappdict[appid], appid, None, None, relayip, None, clientappid, clientip]
		else:
			#unknown appid wirte to log
			if re.search(ipv4_pattern, clientip):
				return [None, appid, clientip, None, relayip, None, None, None]
			else:
				return [None, appid, None, None, relayip, None, None, clientip]
	
	def addinfo_merge(self, apptype=None, appid=None, sessionid=None, frontid=None, userproductinfo=None, remark=None, ipv4=None, mac=None, remarkid=None, relayip=None, relaymac=None, subappid=None, dcerrid=None, ipv6=None):
		addinfo = [apptype, appid, sessionid, frontid, userproductinfo, remark, ipv4, mac, remarkid, relayip, relaymac, subappid, dcerrid, ipv6]
		self.addinfo_format(addinfo)
		return addinfo
	
	def check_and_update(self, currrecord):
		if(currrecord[25] != None):
			try:
				tempstr = currrecord[25].encode('gbk')
				if(len(tempstr) > 1):
					self.evlog.cuserror(f"dcerrid too long: {currrecord[25]}, after update: e, line: {currrecord}")
					currrecord[25] = 'e'
			except Exception as e:
				self.evlog.cuserror(f"dcerrid encodeing error: {currrecord[25]}, after update: e, line: {currrecord}")
				currrecord[25] = 'e'

	def addinfo_format(self, addinfo):
		#sessionid
		if addinfo[2] is not None:
			addinfo[2] = addinfo[2].strip()
		if addinfo[2] == '':
			addinfo[2] = None
		#frontid
		if addinfo[3] is not None:
			addinfo[3] = addinfo[3].strip()
		if addinfo[3] == '':
			addinfo[3] = None
		#ipv4(ip)
		if addinfo[6] is not None:
			addinfo[6] = addinfo[6].strip()
		if addinfo[6] == '':
			addinfo[6] = None
		#mac
		if addinfo[7] is not None:
			addinfo[7] = addinfo[7].strip().replace(':', '').replace('-', '').upper()
		if addinfo[7] == '':
			addinfo[7] = None
		#remarkid
		if addinfo[8] is not None:
			addinfo[8] = addinfo[8].strip().upper()
		if addinfo[8] == '':
			addinfo[8] = None
		#relayip
		if addinfo[9] is not None:
			addinfo[9] = addinfo[9].strip().upper()
		if addinfo[9] == '':
			addinfo[9] = None
		#relaymac
		if addinfo[10] is not None:
			addinfo[10] = addinfo[10].strip().replace(':', '').replace('-', '').upper()
		if addinfo[10] == '':
			addinfo[10] = None
		#subappid
		if addinfo[11] is not None:
			addinfo[11] = addinfo[11].strip()
		if addinfo[11] == '':
			addinfo[11] = None
		#dcerrid
		if addinfo[12] is not None:
			addinfo[12] = addinfo[12].strip()
		if addinfo[12] == '':
			addinfo[12] = None
		#ipv6(transfer ipv6 to upper)
		if addinfo[13] is not None:
			addinfo[13] = addinfo[13].strip().upper()
		if addinfo[13] == '':
			addinfo[13] = None


	def remark_process(self, remarkstr):
		if(remarkstr.replace(' ', '') == ''):
			return [None, None, None, None]
		remarkipv4 = None
		remarkipv6 = None
		remarkmac = None
		remarkid = None
		#ip match (IPv4 and IPv6)
		ipv6_re = re.search(ipv6_pattern, remarkstr)
		if ipv6_re:
			remarkipv6 = ipv6_re.groups()[0]
			remarkstr = remarkstr.replace(remarkipv6, '')

		ipv6_bad_re = re.search(ipv6_bad_pattern, remarkstr)
		if ipv6_bad_re:
			remarkstr = remarkstr.replace(ipv6_bad_re.groups()[0], '')

		ipv4_re = re.search(ipv4_pattern, remarkstr)
		if ipv4_re:
			remarkipv4 = ipv4_re.groups()[0]
			remarkstr = remarkstr.replace(remarkipv4, '')

		#MAC address match
		macaddr_re = re.search(macaddr_pattern, remarkstr)
		if(macaddr_re is not None):
			remarkmac = macaddr_re.groups()[0]
			remarkstr = remarkstr.replace(remarkmac, '')
		
		#delete '-' may in id remarkstr
		remarkstr = remarkstr.replace('-', '')
		#id match
		id_re = re.search(id_pattern, remarkstr)
		if id_re:	
			remarkid = id_re.groups()[0]
			#remarkstr = remarkstr.replace(id_re.groups()[0], '')

		
		return [remarkipv4, remarkipv6, remarkmac, remarkid]	
	
	def additional_info_process(self, addtionalinfo):
		currinfolist = addtionalinfo.split('@')
		if(len(currinfolist) == 11):
			return currinfolist
		else:
			return None

	def update_session_info(self, investorid, addinfo, priority = 1):
		#update session info based on event type
		(apptype, appid, sessionid, frontid, _, _, ipv4, mac, remarkid, relayip, relaymac, subappid, dcerrid, ipv6) = addinfo
		investorid = investorid.strip()
		#if(appid == None or appid.strip() == ''):
			#apptype = '1'
		#key = f"{investorid}@{sessionid}@{frontid}"
		key = f"{investorid}@{sessionid}"
		#print(self.session_info)
		if (key not in self.session_info):
			self.session_info[key] = {
				'apptype': {'value': None, 'priority': 0},
				'appid': {'value': None, 'priority': 0},
				'ipv4': {'value': None, 'priority': 0},
				'mac': {'value': None, 'priority': 0},
				'remarkid': {'value': None, 'priority': 0},
				'relayip': {'value': None, 'priority': 0},
				'relaymac': {'value': None, 'priority': 0},
				'subappid': {'value': None, 'priority': 0},
				'dcerrid': {'value': None, 'priority': 0},
				'ipv6': {'value': None, 'priority': 0},
			}
		if (priority == 1):
			self.update_session_element(key, priority, {
				'apptype': apptype,
				'appid': appid,
				'ipv4': ipv4,
				'mac': mac,
				'remarkid': remarkid,
				'relayip': relayip,
				'relaymac': relaymac,
				'ipv6': ipv6,
			})
		elif (priority == 2):
			self.update_session_element(key, priority, {
				'ipv4': ipv4,
				'mac': mac,
				'remarkid': remarkid,
				'ipv6': ipv6,
			})
			if (self.session_info[key]['apptype']['value'] != '3'):
				addinfo[6] = None
				addinfo[7] = None
				addinfo[13] = None
		elif (priority == 3):
			self.update_session_element(key, priority, {
				'ipv4': ipv4,
				'relayip': relayip,
				'subappid': subappid,
				'dcerrid': dcerrid,
				'ipv6': ipv6,
			})
		#check mac in id, if mac is a part of id, set mac to None
		if(self.session_info[key]['mac']['value'] is not None and self.session_info[key]['remarkid']['value'] is not None and self.session_info[key]['mac']['value'] in self.session_info[key]['remarkid']['value']):
			self.session_info[key]['mac']['value'] = None
		if(self.session_info[key]['relaymac']['value'] is not None and self.session_info[key]['remarkid']['value'] is not None and self.session_info[key]['relaymac']['value'] in self.session_info[key]['remarkid']['value']):
			self.session_info[key]['relaymac']['value'] = None



	def update_session_element(self, elekey, priority, updatedict):
		for key in updatedict:
			'''
			if (key == 'ipv4' and self.session_info[elekey]['ipv4']['value'] is not None):
				if(self.check_ip_private(self.session_info[elekey]['ipv4']['value']) == True and self.check_ip_private(updatedict['ipv4']) == False):
					self.session_info[elekey]['ipv4']['value'] = updatedict[key]
					self.session_info[elekey]['ipv4']['priority'] = priority
			'''
			if updatedict[key] is not None and updatedict[key].strip() != '':
				if (key == 'ipv4' and self.session_info[elekey]['ipv4']['value'] is not None):
					if(self.check_ip_private(self.session_info[elekey]['ipv4']['value']) == True and self.check_ip_private(updatedict['ipv4']) == False):
						self.session_info[elekey]['ipv4']['value'] = updatedict[key]
						self.session_info[elekey]['ipv4']['priority'] = priority
						continue
					elif (self.check_ip_private(self.session_info[elekey]['ipv4']['value']) == False and self.check_ip_private(updatedict['ipv4']) == True):
						continue
				if (key == 'ipv6' and self.session_info[elekey]['ipv6']['value'] is not None):
					if(self.check_ip_private(self.session_info[elekey]['ipv6']['value']) == True and self.check_ip_private(updatedict['ipv6']) == False):
						self.session_info[elekey]['ipv6']['value'] = updatedict[key]
						self.session_info[elekey]['ipv6']['priority'] = priority
						continue
					elif (self.check_ip_private(self.session_info[elekey]['ipv4']['value']) == False and self.check_ip_private(updatedict['ipv4']) == True):
						continue
				if self.session_info[elekey][key]['priority'] < priority:
					self.session_info[elekey][key]['value'] = updatedict[key]
					self.session_info[elekey][key]['priority'] = priority
	
	


if __name__ == '__main__':
	import sys
	import os
	if (sys.argv[1] == '-v'):
		scriptname = os.path.basename(__file__)
		print(f"{scriptname}:{versionstr}")
		sys.exit(0)




	#test code
	from dbfunction import DBFunction
	#db set
	confdict = {}
	confdict['oracle_ip'] = os.getenv('DEVDBIP', '127.0.0.1')
	confdict['oracle_port'] = os.getenv('DEVDBPORT', '1521')
	confdict['oracle_sid'] = os.getenv('DEVDBSID', 'ora')
	confdict['oracle_user'] = os.getenv('DEVDBUSER', 'system')
	confdict['oracle_password'] = os.getenv('DEVDBPASSWORD', 'test1234')
	DBinstance = DBFunction(confdict)
	#currdayeventinfo = DBinstance.get_usereventinfo('20250102', tabname="xhdw.base_s_brokeruserevent")
	#currdayeventinfo = DBinstance.get_usereventinfo('20250103', tabname="xhdw.base_s_brokeruserevent")
	#currdayeventinfo = DBinstance.get_usereventinfo('20250829', tabname="xhdw.base_s_brokeruserevent")
	#currdayeventinfo = DBinstance.get_usereventinfo('20251016', tabname="xhdw.base_s_brokeruserevent")
	#print(currdayeventinfo[:5])
	currdayeventinfo = DBinstance.get_usereventinfo('20250205', tabname="xhdw.test_cm003_1024")
	(directappdict, relayappdict) = DBinstance.get_authcodeinfo(tabname='xhdw.base_authenticationcode')
	ep = EventProcess()
	ep.init_appdict(directappdict, relayappdict)
	ep.init_eventdata(currdayeventinfo)
	ep.process_events()
	ep.display_sessioninfo()
	ep.update_events()
	#evetlist = ep.get_eventdata()
	#DBinstance.insert_event(evetlist, tabname='xhdw.TEST_CM003_BROKERUSEREVENT', operdate='20250102')
	#DBinstance.insert_event(evetlist, tabname='xhdw.TEST_CM003_BROKERUSEREVENT')